﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Util.IO
{
    public class ConcatenatedStream : Stream
    {
        private IEnumerator<Stream> streamEnumerator;
        private Stream currentStream;

        public ConcatenatedStream(IEnumerable<Stream> streams)
        {
            if (streams == null)
                throw new ArgumentNullException("streams");
        
            this.streamEnumerator = streams.GetEnumerator();
            if (streamEnumerator.MoveNext())
                this.currentStream = streamEnumerator.Current;
            else
                throw new ArgumentException("streams must contain at least one stream.");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                while (currentStream != null)
                {
                    currentStream.Dispose();
                    if (streamEnumerator.MoveNext())
                        currentStream = streamEnumerator.Current;
                    else
                        currentStream = null;
                }
            }
            base.Dispose(disposing);
        }

        public override bool CanRead
        {
            get { return currentStream.CanRead; }
        }

        public override bool CanWrite
        {
            get { return currentStream.CanWrite; }
        }

        public override bool CanSeek
        {
            get { return currentStream.CanSeek; }
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            while (true)
            {
                int actual = currentStream.Read(buffer, offset, count);
                if (actual < 0)
                    throw new ArgumentException("The underlying stream returned a negative count.");
                if (actual > 0)
                    return actual;

                // Advance to the next stream.
                currentStream.Dispose();
                if (streamEnumerator.MoveNext())
                    currentStream = streamEnumerator.Current;
                else
                    return 0;
            }
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            throw new NotImplementedException();
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            throw new NotImplementedException();
        }

        public override void Flush()
        {
            currentStream.Flush();
        }

        public override long Position
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public override long Length
        {
            get { throw new NotImplementedException(); }
        }

        public override void SetLength(long value)
        {
            throw new NotImplementedException();
        }
    }
}
